/////// comments ////////////

#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "log.h"
#include "stringutil.h"
#include "timestamp.h"
#include "tEditHandler.h"
#include "world.h"

// Aedit Command definitions...
// (Keep in alphabetical order... it's MUCH easier)
rCmdCommands::rCmdCommands( void ) {
	setName( "commands" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
}

bool rCmdCommands::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string temp;
	unsigned i=0;

	// HEAD Commands...
	if ( character->getLevel() >= HEAD ) {
		buf << "\n\r\t{cHead (level " << HEAD << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = rCommandTable::Instance().getCommands().begin(); it != rCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == HEAD ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// GOD Commands...
	if ( character->getLevel() >= GOD ) {
		i = 0;
		buf << "\n\r\t{cGod (level " << GOD << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = rCommandTable::Instance().getCommands().begin(); it != rCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == GOD ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// BUILDER Commands...
	if ( character->getLevel() >= BUILDER ) {
		i = 0;
		buf << "\n\r\t{cBuilder (level " << BUILDER << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = rCommandTable::Instance().getCommands().begin(); it != rCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == BUILDER ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// Regular Commands...
	buf << "\n\r\t{c-- Commands --{x \n\r";
	i = 0;
	for ( std::vector< Command* >::iterator it = rCommandTable::Instance().getCommands().begin(); it != rCommandTable::Instance().getCommands().end(); ++it ) {
		if ( (*it)->getLevel() == 1 ) {
			if ( i % 6 == 0 ) {
				if ( i )
					buf << "\n\r";
				buf << "  ";
			}
			if ( (*it)->getEnabled() )
				buf << format( 12, (*it)->getName(), temp );
			else
				buf << format( 12, (*it)->getName(), temp, 'w' );
			i++;
		}
	}

	character->Send( buf );

	return true;
}

rCmdDescription::rCmdDescription( void ) {
	setName( "description" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: description    {cedit the description of the current room" );
}

bool rCmdDescription::execute( Character* character, const std::string& args ) {

	character->setTedit( true );
	tEditList::Instance().act( character, args );

	return true;
}

rCmdDig::rCmdDig( void ) {
	setName( "dig" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "dig link make" );
	addSyntax( "dig <direction> <vnum>    {Ccreate a two-way link to the target room" );
	addHelp( "Dig creates a bidirectional link to the target room. If the target room cannot" );
	addHelp( "does not exist, dig will create the room, if possible." );
}

bool rCmdDig::execute( Character* character, const std::string& args ) {
	Room* to = NULL;
	Room* from = character->getRoom();
	std::string s_direction, s_vnum;
	unsigned direction = 0, inverse = 0, vnum = 0;

	split( args, s_direction, s_vnum );
	direction = Exit::string2direction( s_direction );
	inverse = Exit::inverse( direction );
	vnum = atoi( s_vnum.c_str() );

	// Check syntax...
	if ( s_direction.empty() || s_vnum.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	// Get target Room...
	if ( ( to = World::Instance().getRoom( vnum ) ) == NULL ) {
		// Room doesn't exist... let's try to create it...
		rCmdMake make;
		if ( !make.execute( character, s_vnum ) ) {
			return false;
		}
		if ( ( to = World::Instance().getRoom( vnum ) ) == NULL ) {
			// Something bad happened...
			character->Send( "Couldn't find or create room." );
			return false;
		}
	}

	// Everything looks good... let's link 'em up...
	from->getExit( direction )->setThere( true );
	from->getExit( direction )->setPoint( vnum );
	to->getExit( inverse )->setThere( true );
	to->getExit( inverse )->setPoint( from->getVnum() );

	// Send the Character to the target Room...
	CmdGoto go;
	go.execute( character, to_str( to->getVnum() ) );

	return true;
}

rCmdExit::rCmdExit( void ) {
	setName( "exit" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: exit    {Cleave redit mode" );
}

bool rCmdExit::execute( Character* character, const std::string& args ) {

	character->setStatus( CONNECTED );
	character->Send( "You have left Redit mode." );

	return true;
}

rCmdInfo::rCmdInfo( void ) {
	setName( "info" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: info          {Cdisplays data on the current room" );
	addSyntax( "        info <vnum>   {Cdisplays data on the given room" );
}

bool rCmdInfo::execute( Character* character, const std::string& args ) {
	std::string buf;
	Room* room = NULL;
	Exit* exit = NULL;

	if ( args.empty() )
		room = character->getRoom();
	else {
		if ( ( room = World::Instance().getRoom( atoi( args.c_str() ) ) ) == NULL ) {
			character->Send( "That room doesn't exist." );
			return false;
		}
	}

	buf << "\t\t{!WRoom " << room->getVnum() << " Information{x\n\r";
	buf << "Name: {C" << room->getName() << "{x\n\r";
	buf << "Sector: {C" << Room::sector2string( room->getSector() ) << "{x\n\r";
	buf << "Exits...";
	for ( unsigned u=0; u < 6; ++u ) {
		exit = room->getExit( u );
		if ( exit->getThere() )
			buf << "\n\r\t" << exit->direction2string( u ) << ": {C" << exit->getPoint() << "{x";
	}
	buf << "\n\r\n\rDescription...\n\r" << room->getDesc();

	character->Send( buf );

	return true;
}

rCmdLink::rCmdLink( void ) {
	setName( "link" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "unlink dig" );
	addSyntax( "syntax: link <direction> <vnum>   {Ccreates an exit in <direction> the given room" );
}

bool rCmdLink::execute( Character* character, const std::string& args ) {
	std::string s_direction;
	std::string s_vnum;
	Room* from = character->getRoom();
	Room* to = NULL;
	unsigned direction = 0;
	unsigned vnum = 0;

	split( args, s_direction, s_vnum );
	direction = Exit::string2direction( trim( s_direction ) );
	vnum = atoi( s_vnum.c_str() );

	if ( s_direction.empty() || s_vnum.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( ( direction = Exit::string2direction( s_direction ) ) == (unsigned)-1 ) {
		character->Send( "Invalid direction." );
		return false;
	}

	if ( ( to = World::Instance().getRoom( vnum ) ) == NULL ) {
		character->Send( "Room not found." );
		return false;
	}

	from->getExit( direction )->setPoint( vnum );
	from->getExit( direction )->setThere( true );
	character->Send( "Exit " + Exit::direction2string( direction ) + " linked with room " + to_str( to->getVnum() ) );

	return true;
}

rCmdMake::rCmdMake( void ) {
	setName( "make" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "remove dig" );
	setSyntax( "syntax: make <vnum>    {Ccreate a room with the given vnum" );
}

bool rCmdMake::execute( Character* character, const std::string& args ) {
	unsigned vnum = atoi( args.c_str() );
	Area* area = NULL;
	Room* room = NULL;

	// Find the parent Area...
	if ( vnum < START_VNUM || ( area = World::Instance().getParentArea( vnum ) ) == NULL ) {
		character->Send( "Invalid vnum." );
		return false;
	}

	// Check permissions...
	if ( !area->hasPermission( character ) ) {
		character->Send( "You don't have permission to that area." );
		return false;
	}

	// Make sure the Room doesn't already exist...
	if ( ( room = area->getRoom( vnum ) ) != NULL ) {
		character->Send( "That room already exists." );
		return false;
	}

	// Everything's cool... let's add the Room...
	room = area->add( new Room( vnum, area ) );
	character->Send( "Room created successfully." );
	return true;
}

rCmdName::rCmdName( void ) {
	setName( "name" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: name <string>   {Cset the room name to the given value" );
}

bool rCmdName::execute( Character* character, const std::string& args ) {
	std::string name = trim( args );

	if ( name.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	character->getRoom()->setName( name );
	character->Send( "Room name changed to \"" + character->getRoom()->getName() + "\"." );

	return true;
}

rCmdRemove::rCmdRemove( void ) {
	setName( "remove" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: remove <vnum>     {Cremove the room specified by vnum" );
	addHelp( "You cannot delete a room which contains any players." );
}

bool rCmdRemove::execute( Character* character, const std::string& args ) {
	std::string buf;
	unsigned vnum = atoi( args.c_str() );
	unsigned size = 0;
	Area* area = NULL;
	Room* room = NULL;

	// Get our Room...
	if ( ( room = World::Instance().getRoom( vnum ) ) == NULL ) {
		character->Send( "That room cannot be found." );
		return false;
	}

	// Make sure no Characters are in the Room...
	if ( ( size = room->getCharacters().size() ) > 0 ) {
		if ( size == 1 ) {
			character->Send( room->getCharacters().front()->getName() + " is in that room." );
			return false;
		} else {
			for ( std::vector< Character* >::iterator it = room->getCharacters().begin(); it != room->getCharacters().end(); ++it ) {
				if ( (*it) == room->getCharacters().back() )
					buf << " and ";
				else
					buf << ", ";
				buf << (*it)->getName();
			}
			buf << " are in that room right now.";
			character->Send( buf );
			return false;
		}
	}

	area = room->getArea();
	area->drop( room );
	delete room;
	room = NULL;
	character->Send( "Room deleted." );

	return true;
}

rCmdReset::rCmdReset( void ) {
	setName( "reset" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: reset                                 {Cdisplay all room resets" );
	addSyntax( "        reset <o|m> <vnum> <number> <limit>   {Cadd a reset for an object/mob" );
	addSyntax( "        reset - <number>                      {Cremove the given reset" );
	addHelp( "A reset will load <number> Objects/Mobs into the room on each reset" );
	addHelp( "until there are <limit> of that Object in the curren room, or <limit>" );
	addHelp( "of that Mob in the current area.  <vnum> specifies which Object/Mob to" );
	addHelp( "load." );
}

bool rCmdReset::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string input = trim( args );
	std::string type;
	std::string vnum;
	std::string number;
	std::string limit;
	Room* room = character->getRoom();
	Area* area = room->getArea();
	Reset* reset = NULL;
	unsigned u=0;

	if ( input.empty() ) {
		buf << "{WReset{x   {ctype{x   {Mvnum{x   {Bnumber{x   {glimit{x\n\r";
		buf << "----------------------------------------------\n\r";
		for ( std::vector< Reset* >::iterator it = area->getResets().begin(); it != area->getResets().end(); ++it, u++ )
			if ( (*it)->getVnum() == room->getVnum() ) {
				buf << "\n\r" << format( 5, u, 'W' ) << "   {c" << (*it)->type2char() << "   {x   ";
				buf << format( 4, (*it)->getTarget(), 'M' ) << "   ";
				buf << format( 6, (*it)->getNumber(), 'B' ) << "   ";
				buf << format( 5, (*it)->getLimit(), 'g' );
			}
	} else {
		split( args, type, vnum, number, limit );
		if ( type == "-" ) {
			for ( std::vector< Reset* >::iterator it = area->getResets().begin(); it != area->getResets().end(); ++it, ++u )
				if ( u == (*it)->getVnum() ) {
					area->getResets().erase( it );
					break;
				}
			buf << "Reset " << u << " removed.";
		} else {
			area->getResets().push_back( reset = new Reset );
			reset->setVnum( character->getRoom()->getVnum() );
			reset->setType( Reset::string2type( type ) );
			reset->setTarget( atoi( vnum.c_str() ) );
			reset->setNumber( atoi( number.c_str() ) );
			reset->setLimit( atoi( limit.c_str() ) );
		}
	}

	character->Send( buf );

	return true;
}

rCmdRlist::rCmdRlist( void ) {
	setName( "rlist" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: rlist            {Cdisplay all rooms" );
	addSyntax( "        rlist <string>   {Cdisplay all rooms matching the given string" );
}

bool rCmdRlist::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string search = trim( args );
	Area* area = character->getRoom()->getArea();

	if ( search.empty() ) {
		for ( std::vector< Room* >::iterator r_it = area->getRooms().begin(); r_it != area->getRooms().end(); ++r_it )
			buf << "\n\r [ " << format( 5, (*r_it)->getVnum(), 'g' ) << " ]  {G" << (*r_it)->getName() << "{x";
	} else {
		for ( std::vector< Room* >::iterator r_it = area->getRooms().begin(); r_it != area->getRooms().end(); ++r_it )
			if ( strstr( (*r_it)->getName(), search ) )
				buf << "\n\r [ " << format( 5, (*r_it)->getVnum(), 'g' ) << " ]  {G" << (*r_it)->getName() << "{x";
	}

	if ( buf.empty() ) {
		character->Send( "No rooms to display." );
		return false;
	}

	character->Send( buf );

	return true;
}

rCmdSector::rCmdSector( void ) {
	setName( "sector" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "redit" );
	addSyntax( "syntax: sector <value>   {Csets the room sector to the given value" );
	addHelp( "The following sectors are supported:" );
	addHelp( "\t-indoor       -city" );
	addHelp( "\t-forest       -plains" );
	addHelp( "\t-swamp        -mountain" );
	addHelp( "\t-road         -underwater" );
	addHelp( "\t-graveyard    -church" );
	addHelp( "\t-arena" );
}

bool rCmdSector::execute( Character* character, const std::string& args ) {
	std::string input = trim( args );

	if ( input.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	character->getRoom()->setSector( atoi( input.c_str() ) );
	character->Send( "Sector changed to " + Room::sector2string( character->getRoom()->getSector() ) + "." );

	return true;
}

rCmdUnlink::rCmdUnlink( void ) {
	setName( "unlink" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "link dig redit" );
	addSyntax( "syntax: unlink <direction>   {Cremoves the exit in the specified direction" );
}

bool rCmdUnlink::execute( Character* character, const std::string& args ) {
	std::string direction = trim( args );
	Room* room = character->getRoom();
	unsigned dir = 0;

	if ( direction.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( ( dir = Exit::string2direction( direction ) ) == (unsigned)-1 ) {
		character->Send( "Invalid direction." );
		return false;
	}

	room->getExit( dir )->setPoint( 0 );
	room->getExit( dir )->setThere( false );
	character->Send( "The " + Exit::direction2string( dir ) + " exit was unlinked." );

	return true;
}
